package com.rest.impl;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import com.api.model.ApiParameter;
import com.api.model.ApiService;
import com.api.model.ApiServiceMethod;
import com.api.rest.model.RestClass;
import com.api.rest.model.RestMethod;
import com.rest.ApiEnum;
import com.rest.ApiRestService;
import com.rest.ApiServices;
import com.rest.ServicesService;
import com.sun.jersey.core.header.FormDataContentDisposition;
import com.util.IOUtils;
import com.util.JsonParser;
import com.util.PathLocator;

public class ServicesServiceImpl implements ServicesService {

	private final List<ApiServices> apiServices = new ArrayList<ApiServices>();

	private final Map<String, Map<String, ApiRestService>> services = new HashMap<String, Map<String, ApiRestService>>();

	private String apiVersion;

	private final String filePropertyName;
	private final Properties properties;
	private final ApiRestHandler apiRestHandler;
	private String propertiesFile;

	private final EnumsServiceImpl enumsService = new EnumsServiceImpl();

	public ServicesServiceImpl(ApiRestHandler apiRestHandler, String propertiesFile, String filePropertyName) {
		if (apiRestHandler == null || propertiesFile == null || filePropertyName == null) {
			throw new IllegalArgumentException("ApiRestHandler, propertiesFile and filePropertyName cannot be null");
		}
		this.apiRestHandler = apiRestHandler;
		this.filePropertyName = filePropertyName;
		this.propertiesFile = PathLocator.getClassesPath() + propertiesFile;
		this.properties = new Properties();

		try {
			properties.load(new FileInputStream(this.propertiesFile));
		} catch (Exception e) {
			throw new IllegalStateException("Couldn't load properties file " + this.propertiesFile, e);
		}

		String defaultFileName = properties.getProperty(filePropertyName);
		loadApiServices(defaultFileName);
	}

	@Override
	public List<ApiServices> getServices() {
		return apiServices;
	}

	@Override
	public ApiRestService getService(String api, String request) {

		Map<String, ApiRestService> map = null;

		if (!this.services.containsKey(api)) {
			throw new IllegalStateException("Api doesn't exists");
		}
		map = this.services.get(api);
		if (!map.containsKey(request)) {
			throw new IllegalStateException(String.format("Api '%s' doesn't have a service '%s'", api, request));
		}
		return map.get(request);
	}

	@Override
	public String getVersion() {
		return JsonParser.parseToJSon(this.apiVersion);
	}

	@Override
	public String updateServices(InputStream inputStream, FormDataContentDisposition fileDetail) {
		String fileName = apiRestHandler.getJarPath() + fileDetail.getFileName();
		try {
			IOUtils.saveStreamToFile(inputStream, fileName);
			this.apiServices.clear();
			this.services.clear();
			loadApiServices(fileDetail.getFileName());

			properties.setProperty(filePropertyName, fileDetail.getFileName());
			properties.store(new FileOutputStream(propertiesFile), "Api version updated");

		} catch (Exception e) {
			throw new IllegalStateException(String.format("Couldn't update fileName '%s'", fileName), e);
		}
		return "Update ok";
	}

	private void loadApiServices(String jarName) {

		apiRestHandler.loadApiRest(jarName);
		this.apiVersion = apiRestHandler.getApiVersion();

		List<Class<?>> apis = apiRestHandler.getApis();

		for (Class<?> apiClass : apis) {
			String apiName = apiClass.getSimpleName();

			RestClass restClass = apiRestHandler.getRestClass(apiClass);
			List<RestMethod> methods = restClass.getMethods();

			ApiService apiService = apiRestHandler.getApiService(apiClass);
			List<ApiServiceMethod> apiMethods = apiService.getMethods();

			List<String> services = new ArrayList<String>();
			Map<String, ApiRestService> apiServices = new HashMap<String, ApiRestService>();
			for (int i = 0; i < methods.size(); i++) {
				String serviceName = methods.get(i).getName();
				List<ApiParameter> parameters = apiMethods.get(i).getParameters();
				String params = getParameters(parameters);
				serviceName += params;

				ApiRestService restService = new ApiRestService(methods.get(i), apiMethods.get(i));

				services.add(serviceName);
				apiServices.put(serviceName, restService);
			}

			this.apiServices.add(new ApiServices(apiName, services));
			this.services.put(apiName, apiServices);
		}
		Collections.sort(this.apiServices);
		this.enumsService.loadEnumerations(apiRestHandler.getJarPath() + jarName);
	}

	private String getParameters(List<ApiParameter> parameters) {
		String result = "(";
		for (ApiParameter parameter : parameters) {
			if (parameter.isNotNull()) {
				result += "*";
			}
			result += parameter.getName();
			result += ", ";
		}
		if (parameters.size() > 0) {
			result = result.substring(0, result.length() - 2);
		}

		result += ")";
		return result;
	}

	@Override
	public Map<String, List<ApiEnum>> getEnumerations() {
		return this.enumsService.getEnumerations();
	}

}
